package com.myth.mysql2dm.utils;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.Data;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Myth
 * @date 2023/8/9 10:05
 */
public class DataSourceUtil {

    private final static String META_TABLE_NAME = "TABLE_NAME";
    private final static String META_TABLE_SCHEMA_NAME = "TABLE_SCHEM";
    private static final String META_INDEX_NAME = "INDEX_NAME";
    private final static String META_COLUMN_NAME = "COLUMN_NAME";
    private static final String META_REMARKS = "REMARKS";
    private static final String META_TYPE_NAME = "TYPE_NAME";
    private static final String META_COLUMN_SIZE = "COLUMN_SIZE";
    private static final String META_DECIMAL_DIGITS = "DECIMAL_DIGITS";
    private static final String META_IS_NULLABLE = "IS_NULLABLE";
    private static final String META_COLUMN_DEF = "COLUMN_DEF";

    public static boolean existTable(String tableNamePattern) {
        DataSource dataSource = SpringUtil.getBean(DataSource.class);
        Assert.notNull(dataSource, "找不到数据源");
        try (Connection connection = dataSource.getConnection();
             ResultSet resultSet = connection.getMetaData().getTables(connection.getCatalog(), connection.getSchema(), tableNamePattern, null)) {
            return resultSet.next();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 支持模糊搜索, 底层原理是sql的like
     *
     * @param tableNamePattern
     * @return
     */
    public static List<String> tablesLike(String tableNamePattern) {
        List<String> tables = new ArrayList<>(0);
        DataSource dataSource = SpringUtil.getBean(DataSource.class);
        Assert.notNull(dataSource, "找不到数据源");
        try (Connection connection = dataSource.getConnection();
             ResultSet resultSet = connection.getMetaData().getTables(connection.getCatalog(), connection.getSchema(), tableNamePattern, null)) {
            while (resultSet.next()) {
                tables.add(resultSet.getString(META_TABLE_NAME));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return tables;
    }

    public static boolean existIndex(String tableName, String indexName) {
        return indexes(tableName, StrUtil.concat(true, "^", indexName, "$")).size() > 0;
    }

    public static boolean existIndexReg(String tableName, String indexNameReg) {
        return indexes(tableName, indexNameReg).size() > 0;
    }

    /**
     * 模糊查询索引名
     *
     * @param tableName
     * @param indexNameReg 正则表达式
     * @return
     */
    public static List<String> indexes(String tableName, String indexNameReg) {
        List<String> indexes = new ArrayList<>(0);
        DataSource dataSource = SpringUtil.getBean(DataSource.class);
        Assert.notNull(dataSource, "找不到数据源");
        try (Connection connection = dataSource.getConnection()) {
            try (ResultSet resultSet = connection.getMetaData().getIndexInfo(connection.getCatalog(), connection.getSchema(), tableName, false, false)) {
                while (resultSet.next()) {
                    String thisIndexName = resultSet.getString(META_INDEX_NAME);
                    if (ReUtil.isMatch(indexNameReg, thisIndexName)) {
                        indexes.add(thisIndexName);
                    }
                }
            }
            try (ResultSet resultSet = connection.getMetaData().getIndexInfo(connection.getCatalog(), connection.getSchema(), tableName, true, false)) {
                while (resultSet.next()) {
                    String thisIndexName = resultSet.getString(META_INDEX_NAME);
                    if (ReUtil.isMatch(indexNameReg, thisIndexName)) {
                        indexes.add(thisIndexName);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return indexes;
    }

    public static List<TableColumnDTO> tableColumns(String tableNamePattern) {
        List<TableColumnDTO> columns = new ArrayList<>(0);
        DataSource dataSource = SpringUtil.getBean(DataSource.class);
        Assert.notNull(dataSource, "找不到数据源");
        try (Connection connection = dataSource.getConnection();
             ResultSet resultSet = connection.getMetaData().getColumns(connection.getCatalog(), connection.getSchema(), tableNamePattern, null)) {
            while (resultSet.next()) {
                String columnName = resultSet.getString(META_COLUMN_NAME);
                String typeName = resultSet.getString(META_TYPE_NAME);
                int columnSize = resultSet.getInt(META_COLUMN_SIZE);
                int decimalDigits = resultSet.getInt(META_DECIMAL_DIGITS);
                TableColumnDTO columnDTO = new TableColumnDTO();
                columnDTO.setColumnName(columnName);
                String columnType = typeName;
                if (columnSize > 0) {
                    columnType += "(" + columnSize;
                    if (decimalDigits > 0) {
                        columnType += "," + decimalDigits;
                    }
                    columnType += ")";
                }
                columnDTO.setColumnType(columnType);
                columns.add(columnDTO);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return columns;
    }

    @Data
    public final static class TableColumnDTO {
        /**
         * 列名
         */
        private String columnName;

        /**
         * 数据类型
         */
        private String columnType;
    }
}
